
/* =================================================================== */
/* This File Defines All the Double Link Node/List Operation Functions */
/* =================================================================== */


#include "d_link_list.h"
#include "test.h"


DL_LIST *p_list_test = NULL;

int dl_test_main(DL_LIST *p_list_test)
{
	int user_input_test_id = 0;
	int user_input_data = 0;
	int user_tolerance  = TOLERANCE;

	// check if create fail
	if(NULL == p_list_test)
	{
		printf("\r\nDouble link is empty, post event UNEXPECT_NULL_LIST\r\n");
		if(post_dl_event(UNEXPECT_NULL_LIST, INVALID_DATA))
		{
			return -1;
		}
		return 0;
	}

	printf("Now Test Begin!\r\n");

	show_test_info();

	while(scanf("%d",&user_input_test_id))
	{
		switch(user_input_test_id)
		{
			case 0:
			{
				if(test_insert_dl_node_to_head(p_list_test))
				{
					printf("TEST FAIL\r\n");
					return -1;
				}
				break;
			}

			case 1:
			{
				if(test_insert_dl_node_to_tail(p_list_test))
				{
					printf("TEST FAIL\r\n");
					return -1;
				}
				break;
			}

			case 2:
			{	
				if(test_delete_dl_node(p_list_test))
				{
					printf("TEST FAIL\r\n");
					return -1;
				}
				break;
			}

			case 3:
			{	
				if(test_find_dl_node(p_list_test))
				{
					printf("TEST FAIL\r\n");
					return -1;
				}
				break;
			}

			case 4:
			{	
				if(test_change_dl_node_data(p_list_test))
				{
					printf("TEST FAIL\r\n");
					return -1;
				}
				break;
			}

			case 5:
			{
				if(print_dl_node(p_list_test))
				{
					printf("TEST FAIL!\r\n");
					return -1;
				}
				break;
			}	

			case 6:
			{
				printf("TEST OVER!\r\n");
				return 1;
			}

			default:
			{
				printf("Wrong input index, please input again!\r\n");
				break;
			}
		} //switch
		
		show_test_info();
	} // while	
}


DL_NODE *create_dl_node(int data)
{
	DL_NODE *p_new;

	p_new = (DL_NODE *)malloc(sizeof(DL_NODE));

	if(NULL == p_new)
	{
		printf("malloc fail to creat dl_node! \r\n");
		return NULL;
	}

	memset(p_new, 0, sizeof(DL_NODE));

	p_new->data = data;
	
	return p_new;
}

DL_LIST *create_an_empty_dl_list(void)
{
	int i = 0;
	DL_LIST *p_new_list;
	
	p_new_list = (DL_LIST *)malloc(sizeof(DL_LIST));
	
	// if malloc fail, return NULL
	if(NULL == p_new_list)
	{
		printf("malloc fail to creat dl_list! \r\n");
		return NULL;
	}

	// init this new dl_list
	memset(p_new_list, 0, sizeof(DL_LIST));

	return p_new_list;
}

int insert_dl_node_to_head(DL_LIST *p_list, int data)
{
	DL_NODE *p_tmp = NULL;
	DL_NODE *p_new = NULL;	

	p_new = create_dl_node(data);

	if(NULL == p_new)
	{
		printf("fail to create a new node\r\n");
		return -1;
	}

	// if the input dl_list is empty
	if(NULL == p_list->p_head)
	{
		printf("the original dl_node list is empty!\r\n");
		p_list->p_head = p_new;
		p_list->p_tail = p_new;
	}
	else
	{
		// else insert to tail
		(p_list->p_head)->p_prev = p_new;
		p_new->p_next = p_list->p_head;
		p_new->p_prev = NULL;
		p_list->p_head = p_new;
	}

	p_list->node_count++;
	
	printf("insert new dl_node %d to head success\r\n",p_new->data);

	printf("Now, the double node list has %d nodes\r\n",p_list->node_count);
	
	return 0;
}


int insert_dl_node_to_tail(DL_LIST *p_list, int data)
{
	DL_NODE *p_tmp = NULL;
	DL_NODE *p_new = NULL;	

	p_new = create_dl_node(data);

	if(NULL == p_new)
	{
		printf("fail to create a new node\r\n");
		return -1;
	}

	// if the input dl_list is empty
	if(NULL == p_list->p_tail)
	{
		printf("the original dl_node list is empty!\r\n");
		p_list->p_head = p_new;
		p_list->p_tail = p_new;
	}
	else
	{
		// else insert to tail
		(p_list->p_tail)->p_next = p_new;
		p_new->p_prev = p_list->p_tail;
		p_new->p_next = NULL;
		p_list->p_tail = p_new;
	}

	p_list->node_count++;

	printf("insert new dl_node %d to tail success\r\n",p_new->data);

	printf("Now, the double node list has %d nodes\r\n",p_list->node_count);
	
	return 0;
}

int delete_dl_node(DL_LIST *p_list, int data)
{
	DL_NODE *p_tmp = NULL;

	p_tmp = find_dl_node(p_list, data);

	// the specified node doesnt exist
	if(NULL == p_tmp)
	{
		printf("fail to delete dl_node %d, dl_node not found\r\n", data);

		post_dl_event(NODE_NOT_FOUND,data);

		printf("Post dl event NODE_NOT_FOUND\r\n");
		return -1;
	}

	// delete head node
	if(p_tmp == p_list->p_head)
	{
		// only one node in this dl list
		if(NULL == p_tmp->p_next)
		{
			p_list->p_head = NULL;
			p_list->p_tail = NULL;
		}
		else
		{
			(p_tmp->p_next)->p_prev = NULL;
			// change the head node
			p_list->p_head = p_tmp->p_next;
		}
	}
	else if(p_tmp == p_list->p_tail)
	{
		(p_tmp->p_prev)->p_next = NULL;
		// change the tail node
		p_list->p_tail = p_tmp->p_prev;
	}
	else
	{
		(p_tmp->p_prev)->p_next = (p_tmp->p_next);
		(p_tmp->p_next)->p_prev = (p_tmp->p_prev);
	}

	p_list->node_count--;
	free(p_tmp);
	printf("delete dl_node %d success\r\n",data);

	return 0;
}


/* this function will check from head to tail, and return the first matched node */
DL_NODE *find_dl_node(DL_LIST *p_list, int data)
{
	DL_NODE *p_tmp = NULL;

	// check if this dl list is not exist
	if(NULL == p_list)
	{
		printf("this dl_node list doesnt exist, create it first please\r\n");
		return NULL;
	}

	p_tmp = p_list->p_head;

	// check if this is an empty dl list
	if(NULL == p_tmp)
	{
		printf("this is an empty dl_node list, create it first please\r\n");
		return NULL;
	}

	while(p_tmp->data != data)
	{

		// check if finished
		if(NULL == p_tmp->p_next)
		{
			printf("fail to find dl_node with data %d\r\n",data);
			return NULL;
		}
		p_tmp = p_tmp->p_next;
	}
	
	printf("find dl_node with data %d success\r\n",data);
	return p_tmp;
}

int print_dl_node(DL_LIST *p_list)
{
	int node_ind = 1;
	DL_NODE *p_tmp = NULL;

	if(NULL == p_list)
	{
		printf("the dl_node list is empty\r\n");
		return -1;
	}

	p_tmp = p_list->p_head;

	while(NULL != p_tmp)
	{
		printf("	dl_node %d with data %d\r\n",node_ind, p_tmp->data);
		
		// check if it is the last nod
		if(p_tmp == p_list->p_tail)
		{
			printf("	All the %d nodes have been shown above.\r\n",node_ind);
			return 0;
		}
		p_tmp = p_tmp->p_next;
		node_ind++;
	}
	
	// if come here, it is an error
	printf("Error: Unexpected NULL node before tail node!! \r\n");

	return -1;
}

int change_dl_node_data(DL_LIST *p_list, int old_data, int new_data)
{
	DL_NODE *p_tmp = NULL;

	p_tmp = find_dl_node(p_list, old_data);

	if(NULL == p_tmp)
	{
		printf("the dl_node to be changed doesnt exist, please get a new one\r\n");
		if(post_dl_event(NODE_NOT_FOUND,old_data))
		{
			// alloc event fail
			return -1;
		}
		printf("Post dl event NODE_NOT_FOUND\r\n");
		return 0;
	}
	
	p_tmp->data = new_data;
	printf("the dl_node's original data %d has been changed to %d\r\n",old_data, new_data);

	return 0;
}


